package com.ittao.taoaicodeapp.core.builder;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.File;
import java.nio.file.Path;
import java.util.Map;

/**
 * 构建 Vue 项目 - 支持本地和COS模式
 * 根据存储策略自动选择构建方式：
 * - 本地模式：直接在项目目录执行npm构建
 * - COS模式：使用零堆积策略，临时下载-构建-上传-清理
 */
@Slf4j
@Component
public class VueProjectBuilder {

    /**
     * 构建 Vue 项目 - 智能模式选择
     * @param projectPath 项目路径
     * @return 是否构建成功
     */
    public boolean buildProject(Path projectPath) {
        return buildProject(projectPath.toString());
    }

    /**
     * 本地构建Vue项目（String版本）
     * @param projectPath 项目路径
     * @return 是否构建成功
     */
    public boolean buildProject(String projectPath) {
        File projectDir = new File(projectPath);
        if (!projectDir.exists() || !projectDir.isDirectory()) {
            log.error("项目路径无效: {}", projectPath);
            return false;
        }

        // 检查 package.json 是否存在
        File packageJson = new File(projectDir, "package.json");
        if (!packageJson.exists()) {
            log.error("package.json 文件不存在: {}", packageJson.getAbsolutePath());
            return false;
        }

        log.info("开始本地构建Vue项目: {}", projectPath);

        // 执行 npm install
        if (!executeNpmInstall(projectDir)) {
            log.error("npm install 执行失败");
            return false;
        }

        // 执行 npm run build
        if (!executeNpmBuild(projectDir)) {
            log.error("npm run build 执行失败");
            return false;
        }

        // 验证 dist 目录是否生成
        File distDir = new File(projectDir, "dist");
        if (!distDir.exists()) {
            log.error("构建完成但 dist 目录未生成: {}", distDir.getAbsolutePath());
            return false;
        }

        log.info("Vue项目本地构建成功，dist目录: {}", distDir.getAbsolutePath());
        return true;
    }

    /**
     * 执行 npm install 命令
     */
    private boolean executeNpmInstall(File projectDir) {
        log.info("执行 npm install...");
        
        // 先检查npm配置
        String checkConfigCommand = String.format("%s config get registry", buildCommand("npm"));
        log.info("检查npm registry配置...");
        executeCommand(projectDir, checkConfigCommand, 30);
        
        String command = String.format("%s install", buildCommand("npm"));
        return executeCommand(projectDir, command, 300); // 5分钟超时
    }

    /**
     * 执行 npm run build 命令
     */
    private boolean executeNpmBuild(File projectDir) {
        log.info("执行 npm run build...");
        String command = String.format("%s run build", buildCommand("npm"));
        return executeCommand(projectDir, command, 180); // 3分钟超时
    }

    /**
     * 判断当前操作系统是否为 Windows
     */
    private boolean isWindows() {
        return System.getProperty("os.name").toLowerCase().contains("windows");
    }

    /**
     * 根据操作系统构建命令
     * @param baseCommand 基础命令（如 npm、yarn）
     * @return 完整命令（如 npm.cmd）
     */
    private String buildCommand(String baseCommand) {
        if (isWindows()) {
            return baseCommand + ".cmd";
        }
        return baseCommand;
    }

    /**
     * 执行命令
     *
     * @param workingDir 工作目录
     * @param command 命令
     * @param timeoutSeconds 超时时间（秒）
     * @return 是否成功
     */
    private boolean executeCommand(File workingDir, String command, int timeoutSeconds) {
        try {
            log.info("执行命令: {}", command);
            
            // 检查package.json是否存在
            File packageJson = new File(workingDir, "package.json");
            log.info("package.json存在: {}", packageJson.exists());
            
            // 使用ProcessBuilder执行命令
            ProcessBuilder processBuilder = new ProcessBuilder(command.split("\\s+"));
            processBuilder.directory(workingDir);
            
            // 确保继承系统环境变量，包括npm配置
            Map<String, String> env = processBuilder.environment();
            // 显式设置HOME环境变量，确保npm能找到用户配置
            String userHome = System.getProperty("user.home");
            if (userHome != null) {
                env.put("HOME", userHome);
            }
            
            // 强制设置npm registry为正确的镜像源，覆盖可能的错误配置
            env.put("npm_config_registry", "https://registry.npmmirror.com/");
            // 设置npm缓存目录，避免权限问题
            env.put("npm_config_cache", "/tmp/npm-cache");
            // 禁用audit和fund，提高安装速度
            env.put("npm_config_audit", "false");
            env.put("npm_config_fund", "false");
            // 设置其他重要的npm配置
            env.put("npm_config_prefer_offline", "false");
            env.put("npm_config_no_optional", "false");
            // 确保使用正确的用户配置目录
            env.put("NPM_CONFIG_USERCONFIG", userHome + "/.npmrc");
            env.put("NPM_CONFIG_GLOBALCONFIG", "/etc/npmrc");
            
            log.info("设置npm环境变量 - registry: {}, cache: {}", 
                    env.get("npm_config_registry"), env.get("npm_config_cache"));
            
            // 重定向错误流到标准输出，这样可以捕获npm的错误信息
            processBuilder.redirectErrorStream(true);
            
            Process process = processBuilder.start();
            
            // 读取输出信息
            StringBuilder output = new StringBuilder();
            try (java.io.BufferedReader reader = new java.io.BufferedReader(
                    new java.io.InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    output.append(line).append("\n");
                }
            }
            
            boolean finished = process.waitFor(timeoutSeconds, java.util.concurrent.TimeUnit.SECONDS);
            
            if (!finished) {
                log.error("命令执行超时（{}秒），强制终止进程", timeoutSeconds);
                process.destroyForcibly();
                return false;
            }
            
            int exitCode = process.exitValue();
            if (exitCode == 0) {
                log.info("命令执行成功: {}", command);
                return true;
            } else {
                log.error("命令执行失败，退出码: {}, 命令: {}", exitCode, command);
                log.error("npm错误输出: {}", output);
                
                // 简单的错误诊断
                log.error("工作目录: {}", workingDir.getAbsolutePath());
                log.error("工作目录权限 - 可读: {}, 可写: {}", workingDir.canRead(), workingDir.canWrite());
                
                return false;
            }
        } catch (Exception e) {
            log.error("命令执行异常: {}", command, e);
            return false;
        }
    }
    
}
